
import java.awt.Point;

public class AffineGPLocalAligner extends LocalAligner {
	int[][] matrixX;
	int[][] matrixY;
	AffineGPPoint[][] pathX;
	AffineGPPoint[][] pathY;

	public boolean init() {
		super.init();
		matrixX = new int[str1.length() + 1][str2.length() + 1];
		matrixY = new int[str1.length() + 1][str2.length() + 1];

		pathX = new AffineGPPoint[str1.length() + 1][str2.length() + 1];
		pathY = new AffineGPPoint[str1.length() + 1][str2.length() + 1];

		initMatrixs();
		return true;
	}

	private void initMatrixs() {
		for (int i = 0; i < matrix.length; i++) {
			matrix[i][0] = 0;
			matrixX[i][0] = Integer.MIN_VALUE;
			matrixY[i][0] = Integer.MIN_VALUE;
		}
		for (int i = 1; i < matrix[0].length; i++) {
			matrix[0][i] = 0;
			matrixX[0][i] = Integer.MIN_VALUE;
			matrixY[0][i] = Integer.MIN_VALUE;
		}
	}

	protected void getLocalPath(int x, int y) {
		// populate M
		int xM = add(matrixX[x - 1][y - 1], scoreFunction.score(matrix, x, y));
		int yM = add(matrixY[x - 1][y - 1], scoreFunction.score(matrix, x, y));
		int mM = add(matrix[x - 1][y - 1], scoreFunction.score(matrix, x, y));
		int max = Math.max(Math.max(xM, yM), mM);
		max = Math.max(max, 0);
		matrix[x][y] = max;

		// higher
		if (max == xM) {
			path[x][y] = new AffineGPPoint(pathX, x - 1, y - 1);
		} else if (max == mM) {
			path[x][y] = new AffineGPPoint(path, x - 1, y - 1);
		} else if (max == yM) {
			path[x][y] = new AffineGPPoint(pathY, x - 1, y - 1);
		} else {
			path[x][y] = null;
		}

		if (max >= matrixMax) {
			matrixMax = max;
			matrixMaxPoint = new AffineGPPoint(path, x, y);
		}

		// populate X
		int mX = add(matrix[x - 1][y], penaltyFunction.headPenalty(x - 1, y)
				+ penaltyFunction.gapPenalty(x - 1, y));
		int xX = add(matrixX[x - 1][y], penaltyFunction.gapPenalty(x - 1, y));
		if (xX > mX) {
			matrixX[x][y] = xX;
			pathX[x][y] = new AffineGPPoint(pathX, x - 1, y);
		} else {
			matrixX[x][y] = mX;
			pathX[x][y] = new AffineGPPoint(path, x - 1, y);
		}

		// populate y
		int mY = add(matrix[x][y - 1], penaltyFunction.headPenalty(x, y - 1)
				+ penaltyFunction.gapPenalty(x, y - 1));
		int yY = add(matrixY[x][y - 1], penaltyFunction.gapPenalty(x, y - 1));
		if (mY > yY) {
			matrixY[x][y] = mY;
			pathY[x][y] = new AffineGPPoint(path, x, y - 1);
		} else {
			matrixY[x][y] = yY;
			pathY[x][y] = new AffineGPPoint(pathY, x, y - 1);
		}
	}

	protected int add(int i, int j) {
		if (i == Integer.MIN_VALUE) {
			return i;
		}
		if (j == Integer.MIN_VALUE) {
			return j;
		}
		return i + j;
	}

	protected Point getNextPath(Point current) {
		super.getNextPath(current);
		AffineGPPoint curr = (AffineGPPoint) current;
		return curr.getPath()[curr.x][curr.y];
	}
	
	protected boolean isTraceBackEnd(Point point) {
		AffineGPPoint curr=(AffineGPPoint)point;
		if (curr==null) {
			return true;
		}
		if ( curr.getPath()==path) {
			return super.isTraceBackEnd(point);
		}
		return false;
	}

}
